#include "Parser.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


struct _Parser{
     char* lineaAParsear;
	 int numeroArchivo;
	 int offset;				// Indica la posicion de la primer letra de la palabra a parsear, con respecto al 0 del archivo
	 int posicionEnArchivo;		// Representa el cursor dentro del string a parsear.
	 int largoUltimaPalabra; 	
	 int inicioDeLinea;			// Asigna la posicion  0 de la palabra a parsear con respecto a la 0 del archivo.
	 int numeroDePalabra;
};


//********************Funciones internas*********//

//Caracter valido: si es una letra o si es un numero.
bool _CaracterValido(char caracter){
	return (( caracter<123 && caracter>96) || (caracter>47 && caracter<58 ));	
}

char _ConvertirAMinuscula(char caracter){ 
	if(caracter>=65 && caracter<=90)
		caracter=caracter+32;
	return caracter;
}

//***********************************************//


// Crea una Parser.
Parser_t* Parser_crear(char* linea, int numeroArchivo, int posUltimoCaracterLeido, int ultimaPalabra) {
  	if(!linea) return NULL;
  	
  	Parser_t* Parser = malloc(sizeof(Parser_t));
	if(Parser == NULL) return NULL;	
	
	Parser->lineaAParsear = malloc((strlen(linea) + 1) * sizeof(char));
	if(Parser->lineaAParsear == NULL) return NULL;
	
	strcpy(Parser->lineaAParsear,linea);
	Parser->numeroArchivo = numeroArchivo;
	Parser->offset = posUltimoCaracterLeido; 					// Indica la posicion del primer caracter de la palabra parseada con respecto al 0 del archivo archivo.
	Parser->posicionEnArchivo = posUltimoCaracterLeido;			// Cursor dentro de la linea a parsear.
	Parser->largoUltimaPalabra = 0;  							// El largo de la ultima palabra parseada.   
	Parser->inicioDeLinea = posUltimoCaracterLeido;				// Asigna el 0 de la palabra a parsear a la ultima posicion de lo parseado hasta el momento del archivo.
	Parser->numeroDePalabra = ultimaPalabra;	
	return Parser;
}

char* Parser_parsear(Parser_t* Parser) {
	if(!Parser) return NULL;
	
	size_t tam = (strlen(Parser->lineaAParsear)); 

    char* buffer = (char*) malloc((tam + 1) * sizeof(char));
	memset( buffer, 0, tam + 1); 								//Inicializar el string vacio
	if (!buffer) return NULL;

    int i = Parser->posicionEnArchivo;  
  
    char c;
    Parser->largoUltimaPalabra=0;   
    c = _ConvertirAMinuscula(Parser->lineaAParsear[i - Parser->inicioDeLinea]);
    
    int posicionRelativa = (strlen(Parser->lineaAParsear) - 1 + Parser->inicioDeLinea);
    
    // Omitimos todos los caracteres no validos que se encuentren antes de la palabra.
    while(i <= posicionRelativa && !_CaracterValido(c)) {
		i++;	
		c = _ConvertirAMinuscula(Parser->lineaAParsear[i - Parser->inicioDeLinea]);       
	}
	
	Parser->offset = i; 	//Una vez omitidos los caracteres invalidos, afirmamos que estamos en en el primer caracter de la palabra.
	int reubicar=i;			//Guardamos esta posicion para poder escribir en la posicion 0 del string a devovler.
    
    bool encontroPalabra = false;
    // Parseamos la palabara
    while(i <= posicionRelativa && _CaracterValido(c)){
        buffer[i-reubicar] = c;  
        Parser->largoUltimaPalabra++;               
        i++;
        c = _ConvertirAMinuscula(Parser->lineaAParsear[i - Parser->inicioDeLinea]); 
        encontroPalabra = true;
    }
    
	if(encontroPalabra) Parser->numeroDePalabra++;	
	
    // Omitimos todos los caracteres hasta el principio de la siguiente palabra o hasta EOL
    while(i <= posicionRelativa && !_CaracterValido(c)) {
		i++;
		c = _ConvertirAMinuscula(Parser->lineaAParsear[i - Parser->inicioDeLinea]);       
	}
    
	// Terminador de cadenas
    buffer[i - Parser->inicioDeLinea] = '\0';
       	
    // Guardamos donde nos quedamos parados en el string.
    Parser->posicionEnArchivo = i;
    
    /* Reduce la memoria pedida al minimo. */
    char* aux = realloc(buffer, (i-reubicar+1) * sizeof(char));
    if (!aux) return buffer;
    return aux;
    
}

int Parser_LargoUltimaPalabra(Parser_t* Parser) {
	if(!Parser) return -1;
	return Parser->largoUltimaPalabra;
}

// Devuelve true si el parseador termino de parser la linea
bool Parser_TerminoDeParsear(Parser_t* Parser) {
	if(!Parser) return true;
	return (Parser->posicionEnArchivo - 1 == strlen(Parser->lineaAParsear) - 1 + Parser->inicioDeLinea);
}

// Devuelve el numero del archivo del cual corresponde la linea a parsear
int Parser_numeroDelArchivo(Parser_t* Parser) {
	if(!Parser) return -1;
	return Parser->numeroArchivo;	
}

// Devuele el offset del archivo con respecto a la pos 0 del archivo
int Parser_offset(Parser_t* Parser) {
	if(!Parser) return -1;
	return Parser->offset;	
}

// Devuelve la posicion del cursor con respecto al 0 del archivo.
int Parser_posicionEnArchivo(Parser_t * Parser) {
	if(!Parser) return -1;
	return Parser->posicionEnArchivo;
}

// Devuelve el numero de palabra de la ultima palabra parseada
int Parser_numeroDePalabra(Parser_t * Parser) {
	if(!Parser) return -1;
	return Parser->numeroDePalabra;
}
//Destruye el parser
void Parser_destruir(Parser_t * Parser) {
	if(!Parser) return;
	free(Parser->lineaAParsear);
	free(Parser);		
}


